﻿using Microsoft.Extensions.Logging;
using RotovapPlatform.Domain.Business.Interfaces;
using RotovapPlatform.Domain.Business.Recipes.Entities;
using RotovapPlatform.Domain.Business.Storage.Entities;
using RotovapPlatform.Domain.Common;
using RotovapPlatform.Domain.Services.Scheduling;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using RotovapPlatform.Domain.Business.Machine.Enums;
using static RotovapPlatform.Domain.Business.Machine.Enums.ExperimentConfigEnums;
using RotovapPlatform.Domain.Services.Devices;

namespace RotovapPlatform.Application.Services.Scheduling
{
	/// <summary>
	/// 任务调度应用服务实现
	/// </summary>
	public class TaskSchedulingAppService : ITaskSchedulingAppService, IDisposable
	{
		private readonly ILogger<TaskSchedulingAppService> _logger;
		private readonly ITaskSchedulingDomainService _taskSchedulingDomainService;
		private readonly IExperimentGroupRepository _experimentGroupRepository;
		private readonly IExperimentRepository _experimentRepository;
		private readonly IDeviceDomainService _deviceDomainService;
		private bool _disposed = false;

		/// <summary>
		/// 当前实验组变更事件
		/// </summary>
		public event Action<Guid?> CurrentExperimentGroupChanged;

		public TaskSchedulingAppService(
			ILogger<TaskSchedulingAppService> logger,
			ITaskSchedulingDomainService taskSchedulingDomainService,
			IExperimentGroupRepository experimentGroupRepository,
			IExperimentRepository experimentRepository,
			IDeviceDomainService deviceDomainService)
		{
			_logger = logger;
			_taskSchedulingDomainService = taskSchedulingDomainService;
			_experimentGroupRepository = experimentGroupRepository;
			_experimentRepository = experimentRepository;
			_deviceDomainService = deviceDomainService;

			// 订阅领域服务的事件
			_taskSchedulingDomainService.CurrentExperimentGroupChanged += HandleCurrentExperimentGroupChanged;
		}

		/// <summary>
		/// 处理领域服务的当前实验组变更事件
		/// </summary>
		private void HandleCurrentExperimentGroupChanged(object sender, CurrentExperimentGroupChangedEventArgs e)
		{
			try
			{
				_logger.LogInformation($"应用服务收到当前实验组变更通知: {e.ExperimentGroupId}");

				// 转发事件给上层
				OnCurrentExperimentGroupChanged(e.ExperimentGroupId);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "处理当前实验组变更事件时发生错误");
			}
		}

		/// <summary>
		/// 触发当前实验组变更事件
		/// </summary>
		protected virtual void OnCurrentExperimentGroupChanged(Guid? experimentGroupId)
		{
			CurrentExperimentGroupChanged?.Invoke(experimentGroupId);
		}

		/// <summary>
		/// 分解实验组为单个实验任务（并保存到数据库）
		/// </summary>
		/// <param name="experimentGroupId">实验组ID</param>
		/// <returns>分解后的实验列表</returns>
		public async Task<List<Experiment>> DecomposeExperimentGroupAppAsync(Guid experimentGroupId)
		{
			try
			{
				_logger.LogInformation($"应用服务开始分解实验组 {experimentGroupId}");

				// 调用领域服务分解实验组
				var experiments = await _taskSchedulingDomainService.DecomposeExperimentGroupDomainAsync(experimentGroupId);

				_logger.LogInformation($"应用服务分解实验组 {experimentGroupId} 完成，共 {experiments.Count} 个实验");
				return experiments;
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, $"应用服务分解实验组 {experimentGroupId} 时发生错误");
				throw;
			}
		}

		/// <summary>
		/// 分解实验组为单个实验任务（不保存到数据库，仅用于UI显示）
		/// </summary>
		/// <param name="experimentGroupId">实验组ID</param>
		/// <returns>分解后的实验列表</returns>
		public async Task<List<Experiment>> DecomposeExperimentGroupForUIAsync(Guid experimentGroupId)
		{
			try
			{
				_logger.LogInformation($"应用服务开始分解实验组 {experimentGroupId}（仅用于UI显示）");

				// 调用领域服务分解实验组（不保存到数据库）
				var experiments = await _taskSchedulingDomainService.DecomposeExperimentGroupWithoutSavingAsync(experimentGroupId);

				_logger.LogInformation($"应用服务分解实验组 {experimentGroupId} 完成（仅用于UI显示），共 {experiments.Count} 个实验");
				return experiments;
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, $"应用服务分解实验组 {experimentGroupId} 时发生错误（仅用于UI显示）");
				throw;
			}
		}

		/// <summary>
		/// 验证实验组配方
		/// </summary>
		/// <param name="experimentGroupId">实验组ID</param>
		/// <returns>验证结果</returns>
		public async Task<ValidationResultDto> ValidateExperimentGroupAppAsync(string experimentGroupId)
		{
			try
			{
				_logger.LogInformation($"应用服务开始验证实验组 {experimentGroupId} 的配方");

				// 调用领域服务验证实验组配方
				var validationResult = await _taskSchedulingDomainService.ValidateExperimentGroupDomainAsync(experimentGroupId);

				// 转换为DTO
				var resultDto = new ValidationResultDto
				{
					IsValid = validationResult == ValidationResult.Success
				};

				// 如果验证失败，添加错误信息
				if (validationResult != ValidationResult.Success)
				{
					// ValidationResult.ErrorMessage 可能为 null，需要检查
					if (!string.IsNullOrEmpty(validationResult.ErrorMessage))
					{
						resultDto.Errors.Add(validationResult.ErrorMessage);
					}
					else
					{
						resultDto.Errors.Add("验证失败，但未提供具体错误信息");
					}
				}

				_logger.LogInformation($"应用服务验证实验组 {experimentGroupId} 的配方完成，结果：{(resultDto.IsValid ? "通过" : "失败")}");
				return resultDto;
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, $"应用服务验证实验组 {experimentGroupId} 的配方时发生错误");

				// 返回错误结果
				return new ValidationResultDto
				{
					IsValid = false,
					Errors = new List<string> { $"验证过程中发生错误: {ex.Message}" }
				};
			}
		}

		/// <summary>
		/// 启动实验组
		/// </summary>
		/// <param name="experimentGroup">实验组</param>
		/// <returns>操作结果</returns>
		public async Task<OperationResult> StartExperimentGroupAsync(ExperimentGroup experimentGroup)
		{
			try
			{
				_logger.LogInformation($"应用服务开始启动实验组 {experimentGroup.GroupId}");

				// 检查设备当前模式，确保只有在单机自动模式下才能启动实验组
				var deviceDomainService = GetDeviceDomainService();
				var currentMode = await deviceDomainService.GetCurrentDeviceModeAsync();
				if (currentMode != DeviceEnums.DeviceMode.SingleMachineAutomatic)
				{
					_logger.LogWarning($"应用服务: 无法启动实验组，当前设备模式为 {currentMode}，需要单机自动模式");
					return new OperationResult
					{
						Success = false,
						Message = $"无法启动实验组: 设备当前处于{currentMode}模式，请先切换到单机自动模式"
					};
				}

				// 调用领域服务启动实验组
				var operationResult = await _taskSchedulingDomainService.StartExperimentGroupDomainAsync(experimentGroup);

				// 如果实验组启动成功，自动启动第一个实验
				if (operationResult.Success)
				{
					try
					{
						_logger.LogInformation($"实验组 {experimentGroup.GroupId} 启动成功，准备启动第一个实验");
						var firstExperiment = await StartNextExperimentAsync(experimentGroup);

						if (firstExperiment != null)
						{
							_logger.LogInformation($"已启动实验组 {experimentGroup.GroupId} 的第一个实验: {firstExperiment.ExperimentId}");
							operationResult.Message += $"，已启动第一个实验: {firstExperiment.ExperimentName}";

							// 更新设备状态为运行中
							var setStatusResult = await deviceDomainService.SetDeviceModeAsync(DeviceEnums.DeviceMode.SingleMachineAutomatic);
							if (setStatusResult.Success)
							{
								_logger.LogInformation("应用服务: 已将设备状态设置为运行中");

								// 手动触发状态更新为Running
								if (deviceDomainService is DeviceDomainService domainService)
								{
									domainService.UpdateDeviceStatus(DeviceEnums.DeviceStatus.Running);
									_logger.LogInformation("应用服务: 已触发设备状态更新为运行中");
								}
							}
							else
							{
								_logger.LogWarning($"应用服务: 设置设备状态为运行中失败: {setStatusResult.Message}");
							}
						}
					}
					catch (Exception ex)
					{
						// 启动第一个实验失败，但实验组已成功启动，因此仍然返回成功
						_logger.LogWarning(ex, $"启动实验组 {experimentGroup.GroupId} 的第一个实验时发生错误，但实验组已成功启动");
						operationResult.Message += $"，但启动第一个实验失败: {ex.Message}";
					}
				}

				_logger.LogInformation($"应用服务启动实验组 {experimentGroup.GroupId} 完成，结果：{(operationResult.Success ? "成功" : "失败")}");
				return operationResult;
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, $"应用服务启动实验组 {experimentGroup?.GroupId} 时发生错误");
				return new OperationResult { Success = false, Message = $"启动实验组时发生错误: {ex.Message}" };
			}
		}

		/// <summary>
		/// 获取设备领域服务实例
		/// </summary>
		private IDeviceDomainService GetDeviceDomainService()
		{
			// 注意：在实际项目中应通过依赖注入获取，这里用直接访问的方式获取以方便示例
			try
			{
				// 尝试从容器或其他方式获取服务
				// 在实际项目中应该通过构造函数注入IDeviceDomainService
				if (_deviceDomainService == null)
				{
					throw new InvalidOperationException("设备领域服务未初始化");
				}
				return _deviceDomainService;
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "获取设备领域服务时发生错误");
				throw new InvalidOperationException("无法获取设备领域服务", ex);
			}
		}

		/// <summary>
		/// 获取当前活动的实验组ID
		/// </summary>
		/// <returns>当前实验组ID，如果没有活动的实验组则返回null</returns>
		public async Task<Guid?> GetCurrentExperimentGroupIdAsync()
		{
			try
			{
				_logger.LogInformation("应用服务: 获取当前活动的实验组ID");
				return await _taskSchedulingDomainService.GetCurrentExperimentGroupIdAsync();
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "应用服务: 获取当前活动的实验组ID时发生错误");
				throw;
			}
		}

		/// <summary>
		/// 设置当前活动的实验组
		/// </summary>
		/// <param name="experimentGroupId">实验组ID</param>
		/// <returns>操作结果</returns>
		public async Task<OperationResult> SetCurrentExperimentGroupAsync(Guid? experimentGroupId)
		{
			try
			{
				_logger.LogInformation($"应用服务: 设置当前活动的实验组ID为 {experimentGroupId}");

				// 如果ID为null，表示清除当前实验组
				if (experimentGroupId == null)
				{
					await _taskSchedulingDomainService.SetCurrentExperimentGroupAsync(null);
					return new OperationResult { Success = true, Message = "当前实验组已清除" };
				}

				// 验证实验组是否存在
				var experimentGroup = await _experimentGroupRepository.GetByIdAsync(experimentGroupId.Value);
				if (experimentGroup == null)
				{
					_logger.LogWarning($"应用服务: 找不到实验组 {experimentGroupId}");
					return new OperationResult { Success = false, Message = $"找不到实验组 {experimentGroupId}" };
				}

				// 设置当前实验组
				await _taskSchedulingDomainService.SetCurrentExperimentGroupAsync(experimentGroupId);
				return new OperationResult { Success = true, Message = $"当前实验组已设置为 {experimentGroupId}" };
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, $"应用服务: 设置当前活动的实验组ID为 {experimentGroupId} 时发生错误");
				return new OperationResult { Success = false, Message = $"设置当前实验组失败: {ex.Message}" };
			}
		}

		/// <summary>
		/// 启动实验组中的下一个实验
		/// </summary>
		/// <param name="experimentGroup">实验组</param>
		/// <returns>启动的实验实例</returns>
		public async Task<Experiment> StartNextExperimentAsync(ExperimentGroup experimentGroup)
		{
			try
			{
				_logger.LogInformation($"应用服务: 准备启动实验组 {experimentGroup.GroupId} 的下一个实验");

				// 1. 检查实验组状态
				if (experimentGroup.Status != ExperimentGroupStatus.Running)
				{
					_logger.LogWarning($"应用服务: 实验组 {experimentGroup.GroupId} 当前状态为 {experimentGroup.Status}，不能启动新实验");
					throw new InvalidOperationException($"实验组 {experimentGroup.GroupId} 当前状态为 {experimentGroup.Status}，不能启动新实验");
				}

				// 2. 获取下一个待执行的实验
				var pendingExperiments = experimentGroup.Experiments
					.Where(e => e.Status == ExperimentStatus.Pending)
					.OrderBy(e => e.ExecutionOrder)
					.ToList();

				if (!pendingExperiments.Any())
				{
					_logger.LogWarning($"应用服务: 实验组 {experimentGroup.GroupId} 中没有待执行的实验");
					throw new InvalidOperationException($"实验组 {experimentGroup.GroupId} 中没有待执行的实验");
				}

				var nextExperiment = pendingExperiments.First();
				_logger.LogInformation($"应用服务: 获取到实验组 {experimentGroup.GroupId} 的下一个实验: {nextExperiment.ExperimentId}");

				// 3. 更新实验状态
				nextExperiment.Status = ExperimentStatus.Running;
				nextExperiment.ExecutionStartTime = DateTime.Now;
				nextExperiment.CurrentStage = ExperimentStage.MaterialAndConditionPreparation;
				nextExperiment.CurrentSubStage = ExperimentSubStage.NotStarted;

				// 4. 保存实验状态到数据库（仅在启动时保存）
				// 先检查实验是否已存在于数据库
				var existingExperiment = await _experimentRepository.GetByIdAsync(nextExperiment.ExperimentId);
				if (existingExperiment == null)
				{
					// 实验不存在，使用 AddAsync 添加实验
					_logger.LogInformation($"应用服务: 实验 {nextExperiment.ExperimentId} 首次添加到数据库");
					await _experimentRepository.AddAsync(nextExperiment);
				}
				else
				{
					// 实验已存在，使用 UpdateAsync 更新实验
					_logger.LogInformation($"应用服务: 更新实验 {nextExperiment.ExperimentId} 状态");
					await _experimentRepository.UpdateAsync(nextExperiment);
				}

				// 5. 设置当前实验和实验组
				await _taskSchedulingDomainService.SetCurrentExperimentAndGroupAsync(nextExperiment, experimentGroup);

				_logger.LogInformation($"应用服务: 已启动实验组 {experimentGroup.GroupId} 的下一个实验: {nextExperiment.ExperimentId}");
				return nextExperiment;
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, $"应用服务: 启动实验组 {experimentGroup?.GroupId} 的下一个实验时发生错误");
				throw;
			}
		}

		/// <summary>
		/// 获取实验组中所有实验的列表
		/// </summary>
		/// <param name="experimentGroupId">实验组ID</param>
		/// <returns>实验列表</returns>
		public async Task<List<Experiment>> GetExperimentsInGroupAsync(Guid experimentGroupId)
		{
			try
			{
				_logger.LogInformation($"应用服务: 获取实验组 {experimentGroupId} 中的实验列表");

				// 从实验仓储中获取实验组的所有实验
				var experiments = await _experimentRepository.GetByGroupIdAsync(experimentGroupId);

				if (experiments == null || !experiments.Any())
				{
					_logger.LogWarning($"应用服务: 实验组 {experimentGroupId} 中没有找到实验");
					return new List<Experiment>();
				}

				_logger.LogInformation($"应用服务: 获取到实验组 {experimentGroupId} 中的 {experiments.Count()} 个实验");
				return experiments.ToList();
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, $"应用服务: 获取实验组 {experimentGroupId} 中的实验列表时发生错误");
				throw;
			}
		}

		/// <summary>
		/// 获取指定实验的最新状态
		/// </summary>
		/// <param name="experimentId">实验ID</param>
		/// <returns>最新的实验状态</returns>
		public async Task<Experiment> GetExperimentStatusAsync(Guid experimentId)
		{
			try
			{
				_logger.LogInformation($"应用服务: 获取实验 {experimentId} 的最新状态");

				// 从实验仓储中获取实验的最新状态
				var experiment = await _experimentRepository.GetByIdAsync(experimentId);

				if (experiment == null)
				{
					_logger.LogWarning($"应用服务: 实验 {experimentId} 不存在");
					return null;
				}

				_logger.LogInformation($"应用服务: 获取到实验 {experimentId} 的状态，当前状态: {experiment.Status}");
				return experiment;
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, $"应用服务: 获取实验 {experimentId} 的最新状态时发生错误");
				throw;
			}
		}

		/// <summary>
		/// 获取领域服务实例
		/// </summary>
		public ITaskSchedulingDomainService DomainService => _taskSchedulingDomainService;

		/// <summary>
		/// 释放资源
		/// </summary>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// 释放资源
		/// </summary>
		protected virtual void Dispose(bool disposing)
		{
			if (!_disposed)
			{
				if (disposing)
				{
					// 取消事件订阅
					_taskSchedulingDomainService.CurrentExperimentGroupChanged -= HandleCurrentExperimentGroupChanged;
				}

				_disposed = true;
			}
		}
	}
}